package cn.bby.query.example.dao.impl;

import cn.bby.jtk.base.exception.NotSupposedException;
import cn.bby.query.base.constant.QueryCondition;
import cn.bby.query.base.model.req.Filter;
import cn.bby.query.base.model.req.QueryRequest;
import cn.bby.query.base.model.req.QueryResponse;
import cn.bby.query.example.dao.OrderInfoDao;
import cn.bby.query.example.mapper.GoodsInfoMapper;
import cn.bby.query.example.mapper.OrderInfoMapper;
import cn.bby.query.example.model.entity.GoodsInfo;
import cn.bby.query.example.model.entity.OrderInfo;
import cn.bby.query.example.model.entity.vo.OrderInfoVO;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author ben
 * @since 2025/4/12 03:04
 */
@Component
public class OrderInfoDaoImpl implements OrderInfoDao {

    @Resource
    private OrderInfoMapper orderInfoMapper;

    @Resource
    private GoodsInfoMapper goodsInfoMapper;

    @Override
    public QueryResponse<OrderInfoVO> queryList(QueryRequest request) {
        QueryWrapper<OrderInfo> wrapper = Wrappers.query(OrderInfo.class);

        wrapper.lt("id", 1000);
        if (request.getFilters() != null) {
            for (Filter f : request.getFilters()) {
                f.setField(StrUtil.toUnderlineCase(f.getField()));
                switch (f.getCondition()) {
                    case QueryCondition.GREAT_THEN:
                        wrapper.gt(f.getField(), Long.parseLong(f.getValues().get(0)));
                        break;
                    case QueryCondition.LESS_THEN:
                        wrapper.lt(f.getField(), Long.parseLong(f.getValues().get(0)));
                        break;
                    case QueryCondition.EQUALS:
                        if (f.getValues().size() == 1) {
                            wrapper.eq(f.getField(), Long.parseLong(f.getValues().get(0)));
                        } else if (f.getValues().size() > 1) {
                            wrapper.in(f.getField(), f.getValues());
                        } else {
                            throw new NotSupposedException("val is empty");
                        }
                        break;
                    default:
                        Field field = ReflectUtil.getField(OrderInfoVO.class, f.getField());
                        if (field == null) {
                            throw new NotSupposedException("field not found");
                        }
                        if (Number.class.isAssignableFrom(field.getType())) {
                            wrapper.eq(f.getField(), Long.parseLong(f.getValues().get(0)));
                        } else if (String.class.isAssignableFrom(field.getType())) {
                            wrapper.eq(f.getField(), f.getValues().get(0));
                        } else if (Boolean.class.isAssignableFrom(field.getType())) {
                            wrapper.eq(f.getField(), Boolean.parseBoolean(f.getValues().get(0)));
                        } else {
                            throw new NotSupposedException("field type not supported");
                        }
                }
            }
        }
        long total = request.isIgnoreTotal() ? -1 : orderInfoMapper.selectCount(wrapper);
        if (total == 0) {
            return new QueryResponse<>(request);
        }
        Integer page = request.getPage();
        Integer size = request.getSize();
        if (page != null && size != null) {
            wrapper.last(String.format("offset %s limit %s", (page - 1) * size, size));
        }
        wrapper.lambda().orderByAsc(OrderInfo::getId);
        List<OrderInfo> list = orderInfoMapper.selectList(wrapper);
        if (CollUtil.isEmpty(list)) {
            return new QueryResponse<>(request);
        }
        Set<Long> ids = list.stream()
                .map(OrderInfo::getGoodsId)
                .collect(Collectors.toSet());
        QueryWrapper<GoodsInfo> goodsInfoQueryWrapper = Wrappers.query(GoodsInfo.class);
        goodsInfoQueryWrapper.lambda().in(GoodsInfo::getGoodsId, ids);
        Map<Long, GoodsInfo> goodsInfoMap = goodsInfoMapper.selectList(goodsInfoQueryWrapper)
                .stream()
                .collect(Collectors.toMap(GoodsInfo::getGoodsId, goodsInfo -> goodsInfo));
        List<OrderInfoVO> vos = list.stream()
                .map(orderInfo -> {
                    OrderInfoVO vo = new OrderInfoVO();
                    BeanUtil.copyProperties(orderInfo, vo);
                    GoodsInfo goodsInfo = goodsInfoMap.get(orderInfo.getGoodsId());
                    if (goodsInfo != null) {
                        vo.setGoodsPrice(goodsInfo.getPrice());
                        vo.setGoodsName(goodsInfo.getName());
                        vo.setDescription(goodsInfo.getDescription());
                        vo.setGoodsInfo(goodsInfo);
                        vo.setIsTop100(goodsInfo.getId() <= 100);
                        vo.setTop1000(goodsInfo.getId() <= 1000);
                        vo.setTags((goodsInfo.getSellerPhone() + goodsInfo.getName()).chars()
                                .mapToObj(String::valueOf).collect(Collectors.toList()));
                    }
                    return vo;
                }).collect(Collectors.toList());
        return new QueryResponse<>(total, vos, request);
    }

    @Override
    public OrderInfo queryById(Long id) {
        return null;
    }

    @Override
    public int insert(OrderInfo OrderInfo) {
        return 0;
    }

    @Override
    public int insertBatch(List<OrderInfo> entities) {
        return 0;
    }

    @Override
    public int insertOrUpdateBatch(List<OrderInfo> entities) {
        return 0;
    }

    @Override
    public int update(OrderInfo OrderInfo) {
        return 0;
    }

    @Override
    public int deleteById(Long id) {
        return 0;
    }

}
